Function.RegisterNamespace("xUnit.js");

xUnit.js.Stubs=new function(){
    // Public Methods
    this.GetList=function(sourceList,methods,properties){
        if(!Object.IsType(Array,sourceList))throw new Error("xUnit.js.Stubs.GetList: 'sourceList' must be a valid Array.");
        if(!properties)properties={};
        var list=[];
        for(var i=0;i<sourceList.length;i++){
            properties.Source_Value=sourceList[i];
            list.push(this.GetObject(methods,properties));
        }
        delete properties.Source_Value;
        return list;
    };
    
    this.GetMethod=function(param1,param2,paramN,returnValue){
        var methodParameters;
        var methodReturnValue;
        if(arguments.length==1&&Object.IsType(Function,param1)){
            methodParameters=Function.GetParameters(param1);
            methodReturnValue=param1;
        }else{
            methodParameters=Array.prototype.slice.call(arguments,0,arguments.length-1);
            methodReturnValue=arguments.length?arguments[arguments.length-1]:undefined;
        }
        var method=function(){
            // Collect Calling Arguments
            var callingArguments={};
            for(var i=0;i<arguments.length;i++){
                callingArguments[method.Parameters[i]||String.Format("Argument_{0}",i)]=arguments[i];
            }
            
            // Collect Expectation
            var expectedResult=null;
            if(Object.IsType(Function,method.ReturnValue)){
                expectedResult=method.ReturnValue.apply(this,arguments);
            }else{
                expectedResult=method.ReturnValue;
            }

            // Store Invocation
            method.Calls.push({
                Arguments:callingArguments,
                ReturnValue:expectedResult
            });

            return expectedResult;
        };
        method.Calls=[];
        method.Parameters=methodParameters;
        method.ReturnValue=methodReturnValue;
        return method;
    };  

    this.GetObject=function(methods,properties,type){
        var object=Object.create?Object.create(type&&type.prototype||type||null):{};
        if(methods){
            for(var x in methods){
                var parameters=[];
                var returnValue=null;
                if(Object.IsType(Function,methods[x])){
                    returnValue=methods[x];
                }else{
                    parameters=methods[x].parameters||[];
                    returnValue=methods[x].returnValue;
                }
                object[x]=this.GetMethod.apply(this,parameters.concat(returnValue));
            }
        }
        Object.Copy(object,properties);
        return object;
    };
};